package org.bilinc.gz001.dao.interfaces;

import org.bilinc.gz001.entity.interfaces.AbstractEntity;
import org.bilinc.gz001.hibernateUtil.HibernateUtil;
import org.hibernate.Criteria;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.util.List;

public class AbstractDaoImpl<T extends AbstractEntity> {

    @Autowired
    HibernateUtil hibernateUtil;

    Session session;

    Transaction transaction;

    public void saveOrUpdate(T entity) {
        getSessionStartTransaction().saveOrUpdate(entity);
        commitTransaction();
    }

    public void save(T entity) {
        getSessionStartTransaction().save(entity);
        commitTransaction();
    }

    public void delete(Long id) {
        getSessionStartTransaction().delete(get(id));
        commitTransaction();
    }

    public void delete(T entity) {
        getSessionStartTransaction().delete(entity);
        commitTransaction();
    }

    @SuppressWarnings("unchecked")
    public T get(Long id) {
        T t = (T) createCriteriaNoTransaction().add(Restrictions.like("id", id))
                .uniqueResult();
        closeSession();
        return t;
    }

    public void change(T entity) {
        getSessionStartTransaction().update(entity);
        commitTransaction();
    }

    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        List<T> t = createCriteriaNoTransaction().list();
        closeSession();
        return t;
    }

    protected Criteria createCriteriaInTransaction() {
        return getSessionStartTransaction().createCriteria(getEntityClass());
    }

    protected Criteria createCriteriaNoTransaction() {
        return getSession().createCriteria(getEntityClass());
    }

    protected Session getSession() {
        if (session == null) {
            session = hibernateUtil.getSessionFactory().openSession();
            return session;
        }
        if (!session.isOpen()) {
            session = hibernateUtil.getSessionFactory().openSession();
        }
        return session;
    }

    protected Session getSessionStartTransaction() {
        if (getSession().getTransaction() == null) {
            session.beginTransaction();
            return session;
        }
        if (getSession().getTransaction().isActive()) {
            return session;
        }
        getSession().getTransaction().begin();
        return session;
    }



    protected void commitTransaction() {
        getSession().getTransaction().commit();
        session.close();
    }

    protected void closeSession() {
        if (session.isOpen()) {
            session.close();
        }
    }

    @SuppressWarnings("unchecked")
    private Class<T> getEntityClass() {
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

}
